package cn.com.cis.utils.tree;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import cn.com.cis.domain.Privilege;
import cn.com.cis.domain.Role;
import cn.com.cis.domain.User;
import cn.com.cis.service.PrivilegeService;
import cn.com.cis.service.RoleService;
import cn.com.cis.service.UserService;

public class PermissionArrayManager {
	
	private UserService userService;
	
	private RoleService roleService;
	
	private PrivilegeService privilegeService;
	
	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public void setRoleService(RoleService roleService) {
		this.roleService = roleService;
	}
	
	public void setPrivilegeService(PrivilegeService privilegeService) {
		this.privilegeService = privilegeService;
	}
	
	private User user;
	private Set<String> userPermissions;
	private List<Role> userRoles;
	private Set<String> userRolePermissions;
	private boolean isAdmin;
	
	private Role role;
	private Set<String> rolePermissions;
	
	public void setUser(User user) {
		this.user = user;
	}

	public void setRole(Role role) {
		this.role = role;
	}
	
	private boolean setPermissionsForRole = true; // true: 当前正在为角色设置权限， false: 当前正在为用户设置权限
	
	public void isSetPermissionsForRole(boolean setPermissionsForRole) {
		this.setPermissionsForRole = setPermissionsForRole;
	}
	
	private void setRolesForUser(User user) {
		userRoles = roleService.selectRolesByUserId(user.getId());
		for(Role role: userRoles){
			if("admin".equals(role.getRoleName())){
				isAdmin = true;
			}
		}
	}
	
	public List<String> getUrls(){
		Set<String> permissionUrls = new HashSet<String>();
		
		setRolesForUser(user);
		
		if(isAdmin){
			for(String adminUrl : privilegeService.selectAdminUrls()){
				permissionUrls.add(adminUrl);
			}
		} else {
			for(String userUrl : privilegeService.selectCurrentUserUrls(user)){
				permissionUrls.add(userUrl);
			}
			
			
			for(Role role : userRoles){
				for(String roleUrl : privilegeService.selectRoleUrls(role)){
					permissionUrls.add(roleUrl);
				}
			}
		}

		return Arrays.asList(permissionUrls.toArray(new String[]{}));
	}
	
	public Map<String, List<PermissionWithProperties>> getPermissionArray(boolean isBlank){
		
		Map<String, List<PermissionWithProperties>> mapToPage = new HashMap<String, List<PermissionWithProperties>>(); 
		for(Privilege aPrivilege : privilegeService.selectPrivileges()){
			
			String code = aPrivilege.getCode();
			String[] privilegeSplit = code.split(":");

			String parentNodeName = privilegeSplit[privilegeSplit.length - 2];
			List<PermissionWithProperties> childrenNodes = mapToPage.get(parentNodeName);
			if(null == childrenNodes){
				childrenNodes = new ArrayList<PermissionWithProperties>();
				
			}
			
			PermissionWithProperties childNode = new PermissionWithProperties();
			childNode.setCode(code);
			
			if(!isBlank){
				setPermissionProperties(childNode);
			}
			
			childrenNodes.add(childNode);
			mapToPage.put(parentNodeName, childrenNodes);
		}
		
		
		return mapToPage;
	}
	
	public Map<String, List<PermissionWithProperties>> getBlankPermissionArray(){
		return getPermissionArray(true);
	}
	
	public Map<String, List<PermissionWithProperties>> getPermissionArray(){
		return getPermissionArray(false);
	}

	private void setPermissionProperties(PermissionWithProperties node) {
		if(setPermissionsForRole){
			if(isRoleHaveThisPermission(node)){
				node.setEnable(true);
			}
			
			if("admin".equals(role.getRoleName())){
				node.setEditable(false);
			}
		} else {
			
			setRolesForUser(user);
			
			if(isUserRolesHaveThisPermission(node)){
				node.setEnable(true);
				node.setEditable(false);
			} else if(isUserHaveThisPermission(node)){
				node.setEnable(true);
			}
		}
	}

	private boolean isUserHaveThisPermission(PermissionWithProperties node) {
		
		if(isAdmin){
			return true;
		}
		
		if(null == userPermissions){
			userPermissions = new HashSet<String>();
			for(String privilege : userService.selectPermissionsForUser(user.getId())){
				userPermissions.add(privilege);
			}
		}
		
		return userPermissions.contains(node.getCode());
	}

	private boolean isUserRolesHaveThisPermission(PermissionWithProperties node) {
		if(isAdmin){
			return true;
		}
		
		
		if(null == userRolePermissions){
			userRolePermissions = new HashSet<String>();
			for(Role role : userRoles){
				for(String privilege : roleService.selectPermissionsForRole(role.getRoleId())){
					userRolePermissions.add(privilege);
				}
			}
		}
		
		return userRolePermissions.contains(node.getCode());
	}

	private boolean isRoleHaveThisPermission(PermissionWithProperties node) {
		if("admin".equals(role.getRoleName())){
			return true;
		}
		
		if(null == rolePermissions){
			rolePermissions = new HashSet<String>();
			for(String privilege : roleService.selectPermissionsForRole(role.getRoleId())){
				rolePermissions.add(privilege);
			}
		}
		
		return rolePermissions.contains(node.getCode());
	}

}
